# etbox_uploader.py - 多服务配置版ETBOX上传工具
# coder DarionDong
import os
import sys
import requests
import json
import winreg
import tkinter as tk
from tkinter import messagebox, filedialog, ttk
import threading
import time
from pathlib import Path

class ETBOXService:
    def __init__(self, name, url):
        self.name = name
        self.url = url.rstrip('/')
    
    def check_service(self):
        """检查服务状态"""
        try:
            response = requests.get(f"{self.url}/api/system_info", timeout=1)
            return response.status_code == 200
        except:
            return False
    
    def upload_file(self, file_path, progress_callback=None):
        """上传文件到该服务"""
        if not os.path.exists(file_path):
            return False, "文件不存在"
        
        if not self.check_service():
            return False, f"{self.name}服务未启动"
        
        try:
            file_name = os.path.basename(file_path)
            file_size = os.path.getsize(file_path)
            
            # 模拟上传进度
            def simulate_progress():
                for i in range(0, 101, 2):
                    if progress_callback:
                        progress_callback(i, f"正在上传到 {self.name}... {i}%")
                    time.sleep(0.05)
            
            # 启动进度模拟
            # （问就是假的进度条）
            progress_thread = threading.Thread(target=simulate_progress, daemon=True)
            progress_thread.start()
            
            # 实际文件上传
            with open(file_path, 'rb') as f:
                files = {'file': (file_name, f)}
                response = requests.post(
                    f"{self.url}/file/upload", 
                    files=files,
                    timeout=180
                )
            
            # 确保进度达到100%
            if progress_callback:
                progress_callback(100, "上传完成")
                time.sleep(0.5)
            
            if response.status_code == 200:
                return True, f"文件已成功上传到 {self.name}"
            else:
                return False, f"上传到 {self.name} 失败: HTTP {response.status_code}"
                
        except Exception as e:
            return False, f"上传到 {self.name} 出错: {str(e)}"

class ServiceManager:
    def __init__(self):
        self.config_file = Path.home() / '.etbox_services.json'
        self.services = self.load_services()
    
    def load_services(self):
        """从配置文件加载服务列表"""
        #默认配置
        default_services = [
            {"name": "本地ETBOX", "url": "http://127.0.0.1:8812"},
            {"name": "教师电脑", "url": "http://192.168.1.100:8812"}
        ]
        
        try:
            if self.config_file.exists():
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    return [ETBOXService(s['name'], s['url']) for s in data.get('services', default_services)]
            else:
                # 创建默认配置
                self.save_services([ETBOXService(s['name'], s['url']) for s in default_services])
                return self.load_services()
        except Exception as e:
            print(f"加载服务配置失败: {e}")
            return [ETBOXService(s['name'], s['url']) for s in default_services]
    
    def save_services(self, services):
        """保存服务列表到配置文件"""
        try:
            data = {
                'services': [{'name': s.name, 'url': s.url} for s in services]
            }
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            self.services = services
            return True
        except Exception as e:
            print(f"保存服务配置失败: {e}")
            return False
    
    def add_service(self, name, url):
        """添加新服务"""
        new_service = ETBOXService(name, url)
        self.services.append(new_service)
        return self.save_services(self.services)
    
    def remove_service(self, index):
        """移除服务"""
        if 0 <= index < len(self.services):
            self.services.pop(index)
            return self.save_services(self.services)
        return False
    
    def get_available_services(self):
        """获取可用的服务列表"""
        available = []
        for service in self.services:
            if service.check_service():
                available.append(service)
        return available

def show_service_selection(file_path):
    """显示服务选择窗口"""
    service_manager = ServiceManager()
    available_services = service_manager.get_available_services()
    
    if not available_services:
        messagebox.showerror("错误", "没有可用的ETBOX服务！\n请确保至少有一个ETBOX服务在运行。")
        return
    
    # 创建选择窗口
    root = tk.Tk()
    root.title("选择上传服务")
    root.geometry("400x300")
    root.resizable(False, False)
    
    # 居中显示
    root.update_idletasks()
    x = (root.winfo_screenwidth() - root.winfo_width()) // 2
    y = (root.winfo_screenheight() - root.winfo_height()) // 2
    root.geometry(f"+{x}+{y}")
    
    # 标题
    title_label = tk.Label(root, text="选择上传目标", font=("Arial", 14, "bold"))
    title_label.pack(pady=15)
    
    file_label = tk.Label(root, text=f"文件: {os.path.basename(file_path)}", 
                         font=("Arial", 10), fg="gray")
    file_label.pack(pady=5)
    
    # 服务列表框架
    list_frame = tk.Frame(root)
    list_frame.pack(fill="both", expand=True, padx=20, pady=10)
    
    # 服务列表
    services_listbox = tk.Listbox(list_frame, font=("Arial", 11), height=6)
    services_listbox.pack(fill="both", expand=True)
    
    # 添加服务到列表
    for i, service in enumerate(available_services):
        services_listbox.insert(tk.END, f"✅ {service.name}\n    {service.url}")
    
    # 默认选择第一个
    if available_services:
        services_listbox.selection_set(0)
    
    def on_upload():
        selection = services_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请选择一个服务！")
            return
        
        selected_index = selection[0]
        selected_service = available_services[selected_index]
        
        root.destroy()
        show_upload_progress(file_path, selected_service)
    
    def on_cancel():
        root.destroy()
    
    # 按钮框架
    button_frame = tk.Frame(root)
    button_frame.pack(fill="x", padx=20, pady=10)
    
    upload_btn = tk.Button(button_frame, text="开始上传", command=on_upload, 
                          bg="#4CAF50", fg="white", font=("Arial", 10, "bold"),
                          width=12, height=1)
    upload_btn.pack(side="right", padx=5)
    
    cancel_btn = tk.Button(button_frame, text="取消", command=on_cancel,
                          width=10, height=1)
    cancel_btn.pack(side="right", padx=5)
    
    # 绑定双击事件
    def on_double_click(event):
        on_upload()
    
    services_listbox.bind("<Double-Button-1>", on_double_click)
    
    root.mainloop()

def show_upload_progress(file_path, service):
    """显示上传进度窗口"""
    # 创建主窗口
    root = tk.Tk()
    root.title(f"内部测试-BETA 0.1.0-上传到 {service.name}")
    root.geometry("450x220")
    root.resizable(False, False)
    
    # 居中显示
    root.update_idletasks()
    x = (root.winfo_screenwidth() - root.winfo_width()) // 2
    y = (root.winfo_screenheight() - root.winfo_height()) // 2
    root.geometry(f"+{x}+{y}")
    
    # 服务信息
    service_label = tk.Label(root, text=f"目标服务: {service.name}", 
                            font=("Arial", 10, "bold"))
    service_label.pack(pady=5)
    
    # 文件名显示
    file_label = tk.Label(root, text=f"正在上传: {os.path.basename(file_path)}", 
                         font=("Arial", 9))
    file_label.pack(pady=5)
    
    # 进度条
    progress_var = tk.DoubleVar()
    progress_bar = ttk.Progressbar(root, variable=progress_var, maximum=100, length=400)
    progress_bar.pack(pady=10)
    
    # 进度文本
    progress_text = tk.StringVar(value="准备上传...")
    progress_label = tk.Label(root, textvariable=progress_text, font=("Arial", 10, "bold"))
    progress_label.pack()
    
    # 状态文本
    status_text = tk.StringVar(value=f"正在连接 {service.name}...")
    status_label = tk.Label(root, textvariable=status_text, font=("Arial", 9))
    status_label.pack(pady=5)
    
    def update_progress(percent, status):
        """更新进度显示"""
        progress_var.set(percent)
        progress_text.set(f"进度: {percent}%")
        status_text.set(status)
        root.update()
    
    def do_upload():
        """执行上传"""
        success, message = service.upload_file(file_path, update_progress)
        
        # 显示结果
        if success:
            status_text.set("上传完成！")
            progress_text.set("✅ 上传成功")
            root.after(2000, root.destroy)  # 2秒后自动关闭
        else:
            status_text.set(f"上传失败: {message}")
            progress_text.set("❌ 上传失败")
            # 失败时显示关闭按钮
            close_btn = tk.Button(root, text="关闭", command=root.destroy, width=10)
            close_btn.pack(pady=10)
    
    # 在新线程中执行上传
    upload_thread = threading.Thread(target=do_upload, daemon=True)
    upload_thread.start()
    
    # 运行窗口
    root.mainloop()

def show_config_gui():
    """显示配置界面"""
    service_manager = ServiceManager()
    
    root = tk.Tk()
    root.title("ETBOX上传工具 内部测试-BETA 0.1.0 - 服务配置")
    root.geometry("500x400")
    root.resizable(False, False)
    
    # 居中显示
    root.update_idletasks()
    x = (root.winfo_screenwidth() - root.winfo_width()) // 2
    y = (root.winfo_screenheight() - root.winfo_height()) // 2
    root.geometry(f"+{x}+{y}")
    
    # 标题
    title_label = tk.Label(root, text="ETBOX上传工具  - 多服务配置", 
                          font=("Arial", 14, "bold"))
    title_label.pack(pady=15)
    
    # 服务列表框架
    list_frame = tk.LabelFrame(root, text="已配置的服务", font=("Arial", 10, "bold"),
                              padx=10, pady=10)
    list_frame.pack(fill="both", expand=True, padx=20, pady=10)
    
    # 服务列表
    services_listbox = tk.Listbox(list_frame, font=("Arial", 10), height=8)
    services_listbox.pack(fill="both", expand=True, pady=5)
    
    def refresh_services_list():
        """刷新服务列表显示"""
        services_listbox.delete(0, tk.END)
        for i, service in enumerate(service_manager.services):
            status = "✅ 在线" if service.check_service() else "❌ 离线"
            services_listbox.insert(tk.END, f"{service.name} - {service.url} [{status}]")
    
    refresh_services_list()
    
    # 服务操作框架
    service_ops_frame = tk.Frame(list_frame)
    service_ops_frame.pack(fill="x", pady=5)
    
    def add_service():
        """添加新服务"""
        def save_new_service():
            name = name_var.get().strip()
            url = url_var.get().strip()
            
            if not name or not url:
                messagebox.showwarning("警告", "请填写服务名称和URL！")
                return
            
            if service_manager.add_service(name, url):
                messagebox.showinfo("成功", "服务添加成功！")
                refresh_services_list()
                add_window.destroy()
            else:
                messagebox.showerror("错误", "添加服务失败！")
        
        add_window = tk.Toplevel(root)
        add_window.title("添加新服务")
        add_window.geometry("300x200")
        add_window.resizable(False, False)
        add_window.transient(root)
        add_window.grab_set()
        
        # 居中显示
        add_window.update_idletasks()
        x = root.winfo_x() + (root.winfo_width() - add_window.winfo_width()) // 2
        y = root.winfo_y() + (root.winfo_height() - add_window.winfo_height()) // 2
        add_window.geometry(f"+{x}+{y}")
        
        tk.Label(add_window, text="服务名称:", font=("Arial", 10)).pack(pady=10)
        name_var = tk.StringVar()
        name_entry = tk.Entry(add_window, textvariable=name_var, width=30)
        name_entry.pack(pady=5)
        
        tk.Label(add_window, text="服务URL:", font=("Arial", 10)).pack(pady=10)
        url_var = tk.StringVar(value="http://")
        url_entry = tk.Entry(add_window, textvariable=url_var, width=30)
        url_entry.pack(pady=5)
        
        button_frame = tk.Frame(add_window)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="保存", command=save_new_service, width=10).pack(side="left", padx=5)
        tk.Button(button_frame, text="取消", command=add_window.destroy, width=10).pack(side="left", padx=5)
    
    def remove_service():
        """移除选中的服务"""
        selection = services_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请选择一个服务！")
            return
        
        if messagebox.askyesno("确认", "确定要删除这个服务吗？"):
            if service_manager.remove_service(selection[0]):
                messagebox.showinfo("成功", "服务删除成功！")
                refresh_services_list()
            else:
                messagebox.showerror("错误", "删除服务失败！")
    
    def test_services():
        """测试所有服务状态"""
        refresh_services_list()
        messagebox.showinfo("完成", "服务状态检测完成！")
    
    tk.Button(service_ops_frame, text="添加服务", command=add_service, width=12).pack(side="left", padx=5)
    tk.Button(service_ops_frame, text="删除服务", command=remove_service, width=12).pack(side="left", padx=5)
    tk.Button(service_ops_frame, text="检测状态", command=test_services, width=12).pack(side="left", padx=5)
    
    # 功能按钮框架
    func_frame = tk.Frame(root)
    func_frame.pack(fill="x", padx=20, pady=10)
    
    def upload_file():
        """上传文件"""
        file_path = filedialog.askopenfilename(title="选择要上传的文件")
        if file_path:
            root.destroy()
            show_service_selection(file_path)
    
    def add_right_click_menu():
        """添加右键菜单 更改注册表"""
        try:
            # 获取当前脚本路径
            if getattr(sys, 'frozen', False):
                script_path = sys.executable
            else:
                script_path = os.path.abspath(__file__)
                python_exe = sys.executable
                script_path = f'"{python_exe}" "{script_path}"'
            
            menu_name = "上传到ETBOX"
            
            # 为所有文件添加右键菜单
            key_path = f"Software\\Classes\\*\\shell\\{menu_name}"
            key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, key_path)
            winreg.SetValueEx(key, "Icon", 0, winreg.REG_SZ, script_path)
            winreg.CloseKey(key)
            
            command_path = f"{key_path}\\command"
            command_key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, command_path)
            command_value = f'"{script_path}" upload "%1"'
            winreg.SetValueEx(command_key, "", 0, winreg.REG_SZ, command_value)
            winreg.CloseKey(command_key)
            
            messagebox.showinfo("成功", "右键菜单添加成功！")
            
        except Exception as e:
            messagebox.showerror("错误", f"添加右键菜单失败: {str(e)}")
    
    def remove_right_click_menu():
        """移除右键菜单 更改注册表"""
        try:
            menu_name = "上传到ETBOX"
            
            # 移除右键菜单
            key_path = f"Software\\Classes\\*\\shell\\{menu_name}"
            try:
                winreg.DeleteKey(winreg.HKEY_CURRENT_USER, f"{key_path}\\command")
                winreg.DeleteKey(winreg.HKEY_CURRENT_USER, key_path)
            except WindowsError:
                pass
            
            messagebox.showinfo("成功", "右键菜单移除成功")
            
        except Exception as e:
            messagebox.showerror("错误", f"移除右键菜单失败: {str(e)}")
    
    tk.Button(func_frame, text="选择文件上传", command=upload_file, 
              bg="#2196F3", fg="white", font=("Arial", 10, "bold"),
              width=15, height=1).pack(side="left", padx=5)
    
    tk.Button(func_frame, text="添加右键菜单", command=add_right_click_menu,
              width=12, height=1).pack(side="left", padx=5)
    
    tk.Button(func_frame, text="移除右键菜单", command=remove_right_click_menu,
              width=12, height=1).pack(side="left", padx=5)
    
    root.mainloop()

def add_right_click_menu():
    """添加右键菜单（独立函数） 更改注册表"""
    try:
        # 获取当前脚本路径
        if getattr(sys, 'frozen', False):
            script_path = sys.executable
        else:
            script_path = os.path.abspath(__file__)
            python_exe = sys.executable
            script_path = f'"{python_exe}" "{script_path}"'
        
        menu_name = "上传到ETBOX"
        
        # 为所有文件添加右键菜单
        key_path = f"Software\\Classes\\*\\shell\\{menu_name}"
        key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, key_path)
        winreg.SetValueEx(key, "Icon", 0, winreg.REG_SZ, script_path)
        winreg.CloseKey(key)
        
        command_path = f"{key_path}\\command"
        command_key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, command_path)
        command_value = f'"{script_path}" upload "%1"'
        winreg.SetValueEx(command_key, "", 0, winreg.REG_SZ, command_value)
        winreg.CloseKey(command_key)
        
        return True
        
    except Exception as e:
        print(f"添加右键菜单失败: {e}")
        return False

def main():
    if len(sys.argv) > 1 and sys.argv[1] == "upload":
        # 右键上传模式
        if len(sys.argv) > 2:
            file_path = sys.argv[2]
            if os.path.exists(file_path):
                show_service_selection(file_path)
            else:
                # 创建简单窗口显示错误
                root = tk.Tk()
                root.withdraw()
                messagebox.showerror("错误", f"文件不存在: {file_path}")
                root.destroy()
        else:
            root = tk.Tk()
            root.withdraw()
            messagebox.showerror("错误", "未指定文件路径")
            root.destroy()
    else:
        # 配置界面模式
        show_config_gui()

if __name__ == "__main__":
    main()